package models;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.UUID;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;

import org.joda.time.DateMidnight;

import play.data.validation.MaxSize;
import play.data.validation.MinSize;
import play.data.validation.Required;
import play.db.jpa.Model;
import errors.EntityNotFound;

@Entity
public class TimeUser extends Model {

	@Required
	@play.data.validation.Unique(value = "tagId")
	@MaxSize(1000)
	public String tagId;

	@Required
	@MinSize(1)
	@MaxSize(100)
	public String firstName;

	@Required
	@MinSize(1)
	@MaxSize(100)
	public String lastName;

	public String email;
	public String password;

	public boolean isSupervisor;
	public boolean isAdmin;

	@ManyToOne
	public TimeUser supervisor;

	public Workday.WorkdayType lastWorkType;

	@OneToMany(mappedBy = "supervisor", fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
	public List<TimeUser> workers;

	public TimeUser() {
		isAdmin = false;
		isSupervisor = false;
	}

	public void addUsersToSupervisor(List<TimeUser> users) {
		if (isSupervisor) {
			if (workers == null)
				workers = new ArrayList<TimeUser>();
			for (Iterator iterator = users.iterator(); iterator.hasNext();) {
				TimeUser timeUser = (TimeUser) iterator.next();
				if (timeUser.id != this.id) {
					timeUser.supervisor = this;
					workers.add(timeUser);
				}
			}
		}
		save();
	}

	public static TimeUser createRandom() {

		TimeUser user = new TimeUser();
		user.tagId = UUID.randomUUID().toString();
		user.email = user.tagId + "@gmail.com";
		user.save();

		return user;
	}

	public static TimeUser findByTag(String tagId) throws EntityNotFound {
		TimeUser user = find("byTagId", tagId).first();
		if (user != null)
			return user;
		else
			throw new EntityNotFound();
	}

	public void punch(Date when, Workday.WorkdayType dayType, TimeLocation loc) {
		PunchTime timePoint = new PunchTime();
		timePoint.user = this;
		timePoint.loc = loc;
		timePoint.dayType = dayType;
		timePoint.timeStamp = when;
		timePoint.save();

		this.lastWorkType = dayType;
		save();
	}

	@SuppressWarnings("unused")
	private static Boolean testUniqueness(String tagId) {
		TimeUser user;
		try {
			user = findByTag(tagId);
			return false;
		} catch (EntityNotFound e) {
			return true;
		}
	}

	public List<PunchTime> findPointsForDay(Date when) {

		DateMidnight todayBegins = new DateMidnight(new org.joda.time.DateTime(
				when));

		return PunchTime.find("byUserAndTimestampBetween", this,
				todayBegins.plusDays(1).toDate(), todayBegins.toDate()).fetch();
	}

	public String toString() {
		return firstName + "  " + lastName;
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = super.hashCode();
		result = prime * result + ((tagId == null) ? 0 : tagId.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (!super.equals(obj))
			return false;
		if (getClass() != obj.getClass())
			return false;
		TimeUser other = (TimeUser) obj;
		if (tagId == null) {
			if (other.tagId != null)
				return false;
		} else if (!tagId.equals(other.tagId))
			return false;
		return true;
	}

}
